package modelo.escenario;

import java.util.*;

import modelo.auto.*;
import modelo.excepciones.*;
import modelo.juego.Usuario;


public class Taller {


  private LinkedList<ElementoTaller> elementos;
  
  //Constructor
  
  public Taller (LinkedList<ElementoTaller> elementos){
	this.elementos = elementos;  	
  }
  
	/**
	 * Agrega el componente a la lista de componentes del auto del usuario .
	 * Por ahora se considera que 1 usuario tiene solo 1 auto.
	 * @param usr: usuario que compra el componente
	 * @param componente: componente a agregar
	 * @throws UnableToAddElementToListException si no se pudo agregar.
	 * @throws ComponentAlreadyExistsException si intenta comprar un componente que ya tiene
	 * @throw UnableToBuyComponentException si el dinero no le alcanza para comprar el componente 
	 * 										
	 */
  	//VER
	public void comprarComponente(Usuario usr, ElementoTaller componente)throws UnableToBuyComponentException, UnableToAddElementToListException, InvalidMaxMarchaCajaException, ComponentAlreadyExistsException{
		double dinero= usr.getDinero();
		if (dinero >= componente.getPrecio()){
			
			try{
				ElementoTaller elementoExistente = usr.getAuto().obtenerComponente(componente);
				throw new ComponentAlreadyExistsException();
			}
			catch (NoSuchElementException noExisteComponente){
				try{
					usr.getAuto().agregarComponente(componente);
					usr.setDinero(dinero-componente.getPrecio());
				}
				catch (UnableToAddElementToListException noSePuedeAgregar){
					throw noSePuedeAgregar;
				}
				catch (InvalidMaxMarchaCajaException e){
					throw e;
				}
					
			}
		}
		else
			throw new UnableToBuyComponentException();
	} 
	
	/**
	 * Remueve el componente de la lista de componentes del auto del usuario, 
	 * si no puede removerlo porque no existe
	 * @param usr: usuario que quiere remover componente
	 * @param componente
	 * @throws UnableToRemoveElementFromListException si no se puede remover el componente.
	 */	
	public void removerComponente(Usuario usr, ElementoTaller componente) throws UnableToRemoveElementFromListException {

		try{
			usr.getAuto().removerComponente(componente);
		}
		catch (UnableToRemoveElementFromListException noSePudoRemoverComponente){
			throw noSePudoRemoverComponente;
		}
	}
	
	/**
	 * Ajusta el componente subiendole la vida util proporcionalmente al montoAbonado
	 * si el monto es superior al necesario para poner la vida util en 100%, se le devuelve el "vuelto"
	 * @param usr: Usuario
	 * @param componente
	 * @param montoAbonado: El dinero que abona para ajustar el componente dado
	 * 
	 * @throws UnableToAdjustComponentException si no se pudo ajustar.
	 * @throws InvalidMontoAbonadoException si el montoAbonado es <=0 o mayor al dinero que tiene el usuario
	 */
	public void ajustarComponente(Usuario usr, ElementoTaller componente, double montoAbonado)throws UnableToAdjustComponentException, InvalidMontoAbonadoException {
		if ((montoAbonado>0)&& (montoAbonado <= usr.getDinero()) ){
			int indiceNuevo= elementos.indexOf(componente);
			if (indiceNuevo != -1) {
				try{
					Componente componenteActual;
					
					componenteActual = (Componente)usr.getAuto().obtenerComponente(componente);
					
					ElementoTaller elementoNuevo= elementos.get(indiceNuevo);
					double precioComponenteNuevo= elementoNuevo.getPrecio();
					Componente componenteNuevo= (Componente)elementoNuevo;
					double vidaUtilComponenteNuevo= componenteNuevo.getVidaUtil();
					double agregadoDeVidaUtil = (montoAbonado * vidaUtilComponenteNuevo)/ precioComponenteNuevo;
					double vidaUtilActual = componenteActual.getVidaUtil();
					double dineroActual= usr.getDinero();
					if ((vidaUtilActual + agregadoDeVidaUtil) > vidaUtilComponenteNuevo){
						double excedenteVidaUtil= (vidaUtilActual + agregadoDeVidaUtil) - vidaUtilComponenteNuevo;
						double vuelto = (precioComponenteNuevo * vidaUtilComponenteNuevo)/ excedenteVidaUtil;
						double newVidaUtil= vidaUtilActual+agregadoDeVidaUtil - excedenteVidaUtil;
						
						componenteActual.setVidaUtil(newVidaUtil);
						
						
						usr.setDinero(dineroActual-montoAbonado + vuelto);
						
						
					}
					else{
						double newVidaUtil= vidaUtilActual + agregadoDeVidaUtil;
						componenteActual.setVidaUtil(newVidaUtil);
						usr.setDinero(dineroActual-montoAbonado);
					}
				}
				catch (NoSuchElementException noExisteComponente){
					throw noExisteComponente;
				}
				
			}
			else
				throw new UnableToAdjustComponentException();
		}
		else{
			throw new InvalidMontoAbonadoException();
		}
	}
	
	/**
	 * Agrega un nuevo componente al stock del taller
	 * @param componente
	 * @throws UnableToAddElementToListException si no se pudo agregar el componente a lista
	 * 
	 */	
	//ver
	public void agregarStockComponente(ElementoTaller componente)throws UnableToAddElementToListException{
		boolean exito = elementos.add(componente);
		if (!exito){
			throw new UnableToAddElementToListException();
		}
	}
	
	public LinkedList<ElementoTaller> getListaComponentes(){
		return elementos;
	}
	
	
	public LinkedList<ElementoTaller> getListaComponentesAuto(Usuario usr){
		return usr.getAuto().getComponentesAuto();
	} 
	
	public boolean existeComponenteEnStock(ElementoTaller componente){
			
		return this.elementos.contains(componente);
	
	}
}